package com.huaxin.device.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.huaxin.device.dto.ResponseCode;
import com.huaxin.device.dto.ResponseResult;
import com.huaxin.device.dto.enums.CircuitBreakerAction;
import com.huaxin.device.dto.request.CircuitBreakerScheduleCreateReqDTO;
import com.huaxin.device.dto.request.CircuitBreakerSchedulePageListReqDTO;
import com.huaxin.device.dto.request.CircuitBreakerScheduleUpdateReqDTO;
import com.huaxin.device.mapper.CircuitBreakerScheduleMapper;
import com.huaxin.device.mapping.CircuitBreakerScheduleMapping;
import com.huaxin.device.models.CircuitBreakerSchedule;
import com.huaxin.device.service.CircuitBreakerScheduleService;
import com.huaxin.hxenum.enums.DayOfWeek;
import com.huaxin.hxenum.utils.EnumUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.webjars.NotFoundException;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.List;

import static org.springframework.util.StringUtils.hasText;

@Service
@RequiredArgsConstructor
@Slf4j
public class CircuitBreakerScheduleServiceImpl extends ServiceImpl<CircuitBreakerScheduleMapper, CircuitBreakerSchedule> implements CircuitBreakerScheduleService {

    private final ApplicationContext applicationContext;
    private final CircuitBreakerScheduleMapping mapping;
    private final ObjectMapper objectMapper;

    @Override
    public ResponseResult<CircuitBreakerSchedule> create(CircuitBreakerScheduleCreateReqDTO in) {
        if (in == null) {
            return ResponseResult.parameterError(null, "参数不能为空");
        }

        // 处理 repeatDays
        List<Integer> repeatDays = parseRepeatDays(in.getRepeatDays());

        CircuitBreakerSchedule entity = mapping.toEntity(in);

        // 计算下一次触发时间（初始为下次触发）
        entity.setNextTrigger(calculateNextTrigger(entity.getTriggerTime(), repeatDays));

        if (!this.save(entity)) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "创建失败，请稍后重试", null);
        }

        CircuitBreakerSchedule created = this.getById(entity.getId());
        return ResponseResult.ok(created);
    }

    @Override
    public CircuitBreakerSchedule getByScheduleId(String id) {
        if (!hasText(id)) {
            throw new IllegalArgumentException("模板ID不能为空");
        }
        CircuitBreakerSchedule entity = this.getById(id);
        if (entity == null) {
            throw new NotFoundException("未找到指定的断路器定时任务");
        }
        return entity;
    }

    @Override
    public ResponseResult<String> update(CircuitBreakerScheduleUpdateReqDTO in) {
        if (in == null) {
            return ResponseResult.parameterError(null, "参数不能为空");
        }

        // 处理 repeatDays
        List<Integer> repeatDays = parseRepeatDays(in.getRepeatDays());

        CircuitBreakerSchedule entity = this.getByScheduleId(in.getId());
        mapping.updateEntity(in, entity);

        // 重新计算下一次触发时间
        entity.setNextTrigger(calculateNextTrigger(entity.getTriggerTime(), repeatDays));

        if (!this.updateById(entity)) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "更新失败，请稍后重试", null);
        }

        return ResponseResult.ok("更新成功");
    }

    @Override
    public ResponseResult<String> delete(String id) {
        CircuitBreakerSchedule entity = this.getByScheduleId(id);

        if (entity.getIsEnabled()) {
            return ResponseResult.failure(ResponseCode.CUSTOM_BUSINESS_ERROR, "启用状态的任务不允许删除", null);
        }

        boolean removed = this.applicationContext.getBean(CircuitBreakerScheduleService.class).removeById(id);
        if (!removed) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "删除失败，请稍后重试", null);
        }

        return ResponseResult.ok("删除成功");
    }

    @Override
    public ResponseResult<String> enable(String id) {
        CircuitBreakerSchedule entity = this.getByScheduleId(id);

        entity.setIsEnabled(true);
        List<Integer> days = parseRepeatDays(entity.getRepeatDays());
        entity.setNextTrigger(calculateNextTrigger(entity.getTriggerTime(), days));

        if (!this.updateById(entity)) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "启用失败，请稍后重试", null);
        }

        return ResponseResult.ok("启用成功");
    }

    @Override
    public ResponseResult<String> disable(String id) {
        CircuitBreakerSchedule entity = this.getByScheduleId(id);

        entity.setIsEnabled(false);
        if (!this.updateById(entity)) {
            return ResponseResult.failure(ResponseCode.INTERNAL_SERVER_ERROR, "禁用失败，请稍后重试", null);
        }

        return ResponseResult.ok("禁用成功");
    }

    @Override
    public ResponseResult<IPage<CircuitBreakerSchedule>> pageQuery(CircuitBreakerSchedulePageListReqDTO in) {
        if (in == null) {
            return ResponseResult.parameterError(null, "参数不能为空");
        }

        IPage<CircuitBreakerSchedule> page = new Page<>(in.getPageNum(), in.getPageSize());
        LambdaQueryWrapper<CircuitBreakerSchedule> wrapper = new LambdaQueryWrapper<>();

        if (hasText(in.getDeviceId())) {
            wrapper.eq(CircuitBreakerSchedule::getDeviceId, in.getDeviceId());
        }

        // 按操作类型过滤
        if (hasText(in.getAction())) {
            wrapper.eq(CircuitBreakerSchedule::getAction, CircuitBreakerAction.of(in.getAction()));
        }

        // 按是否启用过滤
        if (in.getIsEnabled() != null) {
            wrapper.eq(CircuitBreakerSchedule::getIsEnabled, in.getIsEnabled());
        }

        // 按组织家族ID过滤
        if (hasText(in.getFamilyId())) {
            wrapper.eq(CircuitBreakerSchedule::getFamilyId, in.getFamilyId());
        }

        // 按关键字过滤
        if (hasText(in.getKeyword())) {
            wrapper.like(CircuitBreakerSchedule::getScheduleName, in.getKeyword());
        }

        // 按创建时间排序
        wrapper.orderByDesc(CircuitBreakerSchedule::getCreatedAt);

        IPage<CircuitBreakerSchedule> result = this.page(page, wrapper);
        return ResponseResult.ok(result);
    }

    // ================== 工具方法 ==================

    private LocalDateTime calculateNextTrigger(LocalTime triggerTime, List<Integer> repeatDays) {
        if (repeatDays == null || repeatDays.isEmpty()) {
            return LocalDateTime.now().with(triggerTime).plusDays(1); // 默认明天
        }

        ZonedDateTime now = ZonedDateTime.now();
        LocalTime time = triggerTime;

        for (int i = 0; i < 8; i++) { // 最多查8天（跨一周）
            ZonedDateTime candidate = now.plusDays(i).with(time);
            int dayOfWeek = candidate.getDayOfWeek().getValue() % 7 + 1; // 1=周日, 7=周六
            if (repeatDays.contains(dayOfWeek) && !candidate.isBefore(now)) {
                return candidate.toLocalDateTime();
            }
        }

        // 默认返回一周后
        return now.plusWeeks(1).with(time).toLocalDateTime();
    }

    private List<Integer> parseRepeatDays(String repeatDaysJson) {
        if (!hasText(repeatDaysJson)) {
            return List.of();
        }
        try {
            List<Integer> repeatDays = objectMapper.readValue(repeatDaysJson, new TypeReference<List<Integer>>() {
            });
            boolean isValid = EnumUtils.isValidValues(DayOfWeek.class, DayOfWeek::getCode, repeatDays);
            if (!isValid) {
                throw new IllegalArgumentException("重复周期格式错误");
            }
            return repeatDays;
        } catch (JsonProcessingException e) {
            throw new IllegalArgumentException("解析重复周期失败: " + repeatDaysJson);
        }
    }
}